package model

import (
	"gitee.com/wydcn/go-tools/conv/str"
	"gitee.com/wydcn/go-tools/conv/bytes"
)

type ConnectOption struct {
	ClientID []byte
	// userName is the User Name of the payload.
	UserName []byte
	// password is the Password of the payload.
	Password []byte
	// cleanSession is the Clean Session of the variable header.
	CleanSession bool
	// keepAlive is the Keep Alive of the variable header.
	KeepAlive uint16
	// willTopic is the Will Topic of the payload.
	WillTopic []byte
	// willMessage is the Will Message of the payload.
	WillMessage []byte
	// willQoS is the Will QoS of the variable header.
	WillQoS byte
	// willRetain is the Will Retain of the variable header.
	WillRetain bool
}



func (option *ConnectOption) WillFlag() bool{
	return len(option.WillTopic) > 0 && len(option.WillMessage) > 0
}

func Intance() *BasePackage{
	connectOption := ConnectOption{
		ClientID:str.StringToBytes("ClientId"),
		UserName:str.StringToBytes("userName"),
		Password:str.StringToBytes("password"),
		CleanSession:false,
		KeepAlive:uint16(120),
	}

	varHeader := VariableHeader{
		ProtocolName:[]byte{
			0x00,             // Length MSB (0)
			0x04,             // Length LSB (4)
			0x4D,             // 'M'
			0x51,             // 'Q'
			0x54,             // 'T'
			0x54,             // 'T'
			0x04,             // Level(4)
		},
		ProtocolLevel:0x04, //3.1.1版协议，协议级别字段的值是4(0x04)
		ConnectFlags:setConnectFlags(&connectOption),
		KeepAlive: bytes.Uint16ToBytes(connectOption.KeepAlive),
	}

	payLoad := PayLoad{}

	payLoad.LoadPayLoad(&connectOption)

	connPackage := BasePackage{
		PayLoad:payLoad,
	}

	connPackage.VariableHeader = append(varHeader.ProtocolName,varHeader.ProtocolLevel,varHeader.ConnectFlags)
	connPackage.VariableHeader = append(connPackage.VariableHeader,varHeader.KeepAlive...)

	fixedHeader := FixedHeader{}
	fixedHeader = append(fixedHeader,CONNECT<<4)
	rl :=encodeLength(uint32(len(connPackage.VariableHeader) + len(connPackage.PayLoad)))
	appendRemainingLength(fixedHeader,rl)

	connPackage.FixedHeader = fixedHeader

	return &connPackage;
}

func appendRemainingLength(b []byte, rl uint32) []byte {
	// Append the Remaining Length to the slice.
	switch {
	case rl&0xFF000000 > 0:
		b = append(b, byte((rl&0xFF000000)>>24))
		fallthrough
	case rl&0x00FF0000 > 0:
		b = append(b, byte((rl&0x00FF0000)>>16))
		fallthrough
	case rl&0x0000FF00 > 0:
		b = append(b, byte((rl&0x0000FF00)>>8))
		fallthrough
	default:
		b = append(b, byte(rl&0x000000FF))
	}

	// Return the slice.
	return b
}

func encodeLength(n uint32) uint32 {
	var value, digit uint32

	for n > 0 {
		if value != 0 {
			value <<= 8
		}

		digit = n % 128

		n /= 128

		if n > 0 {
			digit |= 0x80
		}

		value |= digit
	}

	return value
}


func setConnectFlags(connOption *ConnectOption) byte{
	var b byte

	// Set 1 to the Bit 7 if the Packet has the User Name.
	if len(connOption.UserName) > 0 {
		b |= 0x80
	}

	// Set 1 to the Bit 6 if the Packet has the Password.
	if len(connOption.Password) > 0 {
		b |= 0x40
	}

	// Set 1 to the Bit 5 if the Will Retain is true.
	if connOption.WillRetain {
		b |= 0x20
	}

	// Set the value of the Will QoS to the Bit 4 and 3.
	b |= connOption.WillQoS << 3

	// Set 1 to the Bit 2 if the Packet has the Will Topic and the Will Message.
	if connOption.WillFlag() {
		b |= 0x04
	}

	// Set 1 to the Bit 1 if the Clean Session is true.
	if connOption.CleanSession {
		b |= 0x02
	}

	// Return the byte.
	return b
}



